#include "RpcSessionBase.h"
#include "IdManager.h"
#include "SessionManager.h"
#include "ServerManager.h"
#include "IPacketParser.h"
#include "LogEx.h"
#include "StackTrace.h"
#include <string>
#include "msg_common.h"
#include "msg_msgid.h"
#include "msg_dbcommon.h"
#include "msg_center.h"
#include "Utils.h"
#include "Hall.h"
using namespace std;
using namespace SGLib;

static char* ConvertIpToStr(u32 ip)
{
    struct in_addr in;
#if _USE_WIN32
    in.S_un.S_addr = ip;
#else
    in.s_addr = ip;
#endif
    return inet_ntoa( in );
}
    
s32 CRpcSessionBase::m_aliveInterval = 60; // sec

CRpcSessionBase::CRpcSessionBase(s32 id) : 
    CIoSocketEx(id)
{
    m_serverId = 0;
	m_sessionId = 0;
    m_aliveTimer = -1;
    m_lastBeat = 0;
}

CRpcSessionBase::~CRpcSessionBase()
{
}
    
void CRpcSessionBase::OnClose()
{
	LOG_INFO( "CRpcSessionBase::OnClose [%llu]", GetServerId() );
   
    u64 sid = GetServerId();
    CServerManager::Instance().DelTimer( m_aliveTimer );
    CSessionManager::Instance().RpcClosed( GetServerId() );
    _SetSessionId( 0 );
	m_serverId = 0;
    m_aliveTimer = -1;
    
    _StartReconnect( sid );
}

void CRpcSessionBase::OnConnect(UserData &ud)
{
    m_serverId = ud.u64d;
    _SetSessionId( CIdManager::Instance().GetNextId() );
    _RegisterOnServer();
    
    CSessionManager::Instance().RpcConnected( GetServerId(), this );
    
    _StartKeepAlive();

	LOG_INFO( "CRpcSessionBase::OnConnect [%llu] socket[%d]", m_serverId, GetSocket() );
}

void CRpcSessionBase::OnConnectError(UserData &ud)
{
    LOG_ERROR( "CRpcSessionBase::OnConnectError sid[%llu][%s:%d] try reconnect",
        ud.u64d, ConvertIpToStr(m_remoteIp), m_remotePort );
    
    CSessionManager::Instance().RpcClosed( ud.u64d );
    _StartReconnect( ud.u64d );
}

void CRpcSessionBase::OnRecv(const byte *pkg, s32 len)
{
	IPacketParser *parser = _GetPacketParser();
	SELF_ASSERT( parser, return; );
	u32 msgid = parser->GetMsgId( pkg );
	s32 headlen = parser->GetHeadLen();
	pkg += headlen;
	len -= headlen;
    
    switch( msgid )
    {
    case commonproto::KEEP_ALIVE:
        m_lastBeat = (s64)time(NULL);
        break;
    case dbcommon::DBPROXY_GAME_USER_LOGIN_RSP:
		CHall::Instance().OnMsgDBProxyUserLogin( pkg, len );
        break;
    case msgid::CENTER_SERVER_GET_USER_MONEY_RSP:
		CHall::Instance().OnMsgCenterUserGetMoney( pkg, len );
        break;
    case msgid::CENTER_SERVER_UPDATE_USER_MONEY_RSP:
		CHall::Instance().OnMsgCenterUserUpdateMoney( pkg, len );
        break;
    case dbcommon::DBPROXY_GAME_LOAD_ACTIVITY_DATA_RSP:
		CHall::Instance().OnMsgDBProxyUserActivityData( pkg, len );
        break;
    case dbcommon::DBPROXY_GAME_LOAD_ITEMS_RSP:
		CHall::Instance().OnMsgDBProxyLoadUserItems( pkg, len );
        break;
    case dbcommon::DBPROXY_GAME_CARDTYPE_AWARD_RSP:
		CHall::Instance().OnMsgDBProxyCardTypeAward( pkg, len);
	  break;	
    case msgid::ROOMCENTER_GAME_ROOM_CREATE:
		CHall::Instance().OnMsgRoomCenterCreatRoom( pkg, len );
        break;
    case msgid::CENTER_SERVER_USER_RECHARGE:
		CHall::Instance().OnMsgCenterUserRecharge( pkg, len );
        break;
    default:
	    _OnMessage( msgid, pkg, len );
        break;
    };
}

CIoSocketEx* CRpcSessionBase::Clone(s32 id)
{
    return new CRpcSessionBase( id );
}

u64 CRpcSessionBase::GetSessionId()
{
    return m_sessionId;
}

u64 CRpcSessionBase::GetServerId()
{
    return m_serverId;
}

bool CRpcSessionBase::SendMsg(u32 msgid, const IMessage &msg)
{
    IPacketParser *parser = _GetPacketParser();
    SELF_ASSERT( parser, return false; );

    CHECK_SERIALIZE_MSG(msgid, msg, parser, return false;);
    if( !Send((byte*)msgbuffer, msglen) )
    {
        LOG_ERROR( "CRpcSessionBase::SendMsg send failed. msgid[%u]", msgid );
        return false;
    }

   return true;
}

bool CRpcSessionBase::SendMsgWithHead(u32 msgid, const IMessage &msg, char *head, int len)
{
	IPacketParser *parser = _GetPacketParser();
	SELF_ASSERT( parser, return false; );
	
	char buf[CIoSocketEx::E_MaxPkg_Len];

	s32 headlen = parser->GetHeadLen();
	s32 msglen = msg.SerializeToArray( buf+headlen+len, sizeof(buf)-headlen-len );
	if( msglen == IMessage::E_Error )
	{
		return false;
	}

	memcpy( buf+headlen, head, len );

	s32 totallen = msglen + headlen + len;
	parser->FillHeader( (byte*)buf, totallen, msgid );

	if( !Send((byte*)buf, totallen) )
	{
		LOG_ERROR( "CRpcSessionBase::SendMsgWithHead send failed. msgid[%u]", msgid );
		return false;
	}

	return true;
}

void CRpcSessionBase::KeepAlive()
{
    commonproto::KeepAlive msg;
    SendMsg( commonproto::KEEP_ALIVE, msg ); 
}

bool CRpcSessionBase::IsAlive()
{
    s64 now = (s64)time(NULL);
    s64 interval = now - m_lastBeat;
    if( interval <= (s64)m_aliveInterval )
    {
        return true;
    }
    return false;
}

void CRpcSessionBase::_Clean()
{
    m_sessionId = 0;
    m_serverId = 0;
    m_lastBeat = (s64)time(NULL);
}

void CRpcSessionBase::_SetSessionId(u64 id)
{
    m_sessionId = id;
}

void CRpcSessionBase::_KeepAliveTimerCallback(void *data, s32 len)
{
    if( !data )
    {
        LOG_ERROR( "[%s][%s][%d] data NULL", __FILE__, __FUNCTION__, __LINE__ );
        return;
    }

    TimerData *td = (TimerData*)data;
    CRpcSessionBase *s = (CRpcSessionBase*)td->data;
    if( s )
    {
        s->KeepAlive();
    }
    else
    {
        LOG_ERROR( "[%s][%s][%d] session NULL", __FILE__, __FUNCTION__, __LINE__ );
    }
}

void CRpcSessionBase::_ReconnectTimerCallback(void *data, s32 len)
{
    if( !data )
    {
        LOG_ERROR( "[%s][%s][%d] data NULL", __FILE__, __FUNCTION__, __LINE__ );
        return;
    }

    TimerData *td = (TimerData*)data;
    u64 sid = td->param;
    CSessionManager::Instance().RpcConnect( sid );
}

void CRpcSessionBase::_RegisterOnServer()
{
    msgid::ServerRegister msg;
    msg.serverid = CServerManager::Instance().GetId();
    SendMsg( msgid::SERVER_REGISTER, msg );
    
    LOG_INFO( "[%s][%s][%d] curserverid[%llu]", __FILE__, __FUNCTION__, __LINE__, msg.serverid );
}

void CRpcSessionBase::_StartKeepAlive()
{
    TimerData data;
    data.data = this;
    m_aliveTimer = CServerManager::Instance().AddTimer(
            E_Session_Alive_Timer,
            _KeepAliveTimerCallback,
            &data, sizeof(data), true );
    if( m_aliveTimer == -1 )
    {   
        LOG_ERROR( "[%s][%s][%d]", __FILE__, __FUNCTION__, __LINE__ );
    }   
}

void CRpcSessionBase::_StartReconnect(u64 serverid)
{
    TimerData data;
    data.param = serverid;
    s32 tid = CServerManager::Instance().AddTimer(
            E_Session_Reconnect_Timer,
            _ReconnectTimerCallback,
            &data, sizeof(data), false );
    if( tid == -1 )
    {   
        LOG_ERROR( "[%s][%s][%d]", __FILE__, __FUNCTION__, __LINE__ );
    }   

    //CSessionManager::Instance().RpcConnect( serverid );
}




